package com.sg.java.apps;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.core.text.csv.CsvWriter;
import cn.hutool.core.util.NumberUtil;
import com.sg.java.entity.YhVo;
import com.sg.java.util.FormulaUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class RWCsv {

    private static final Logger              log = LoggerFactory.getLogger(RWCsv.class);
    private static final Map<String, String> map = new HashMap<>();
    private static final SimpleDateFormat    sdf = new SimpleDateFormat("yyyyMMdd");

    public static void main(String[] args) throws Exception {
        String csvDirPath = args[0];
//        String csvDirPath = "C:/Users/HUAWEI/Desktop/ttt/GGG";
        File csvDir = new File(csvDirPath);
        assert csvDir.isDirectory();
        File[] csvs = csvDir.listFiles();
        if (csvs == null) {
            log.info("该目录下无csv文件:{}", csvDir);
            return;
        }
        log.info("开读");
        long           read_s  = System.currentTimeMillis();
        List<String[]> removes = new ArrayList<>();
        long           total   = 0;
        //todo
        final int rawArrayLength    = 16;
        final int targetArrayLength = 22;
        for (File csv : csvs) {
            String dateStr = csv.getName().substring(0, 8);
            Date   date    = sdf.parse(dateStr);
            log.info("当前csv:{} 当前日期:{}", csv.getAbsolutePath(), dateStr);
            String[] raw = null;
            try (FileReader fr = new FileReader(csv); BufferedReader br = new BufferedReader(fr)) {
                long   tmpCount = 0;
                String line;
                while ((line = br.readLine()) != null) {
                    try {
                        List<String> rawList  = new ArrayList<>();
                        int          quote    = 0;
                        final char[] chars    = line.toCharArray();
                        int          subIndex = 0;
                        for (int i = 0; i < chars.length; i++) {
                            char c = chars[i];
                            if (c == '\"') {
                                quote++;
                            }
                            else if (c == ',') {
                                //双数引号，则此逗号可作为分隔符
                                if (quote % 2 == 0) {
                                    rawList.add(line.substring(subIndex, i));
                                    subIndex = i + 1;
                                }
                            }
                        }
                        rawList.add(line.substring(subIndex));
                        raw = rawList.toArray(new String[0]);
                        tmpCount++;
                        total++;
                        if (raw.length < rawArrayLength) {
                            throw new RuntimeException();
                        }
                        String   meterId = raw[0];
                        String[] other   = get(raw, date);
                        String[] dayData = new String[targetArrayLength];
                        dayData[0] = raw[0];
//                        dayData[1] = raw[23];
                        dayData[2] = raw[1];
//                        dayData[3] = raw[8];
                        dayData[4] = raw[2];
//                        dayData[5] = raw[20];
                        dayData[6]  = raw[3];
                        dayData[7]  = other[8];
                        dayData[8]  = other[9];
                        dayData[9]  = other[10];
                        dayData[10] = other[11];
                        dayData[11] = raw[8];
                        dayData[12] = raw[9];
                        dayData[13] = other[0];
                        dayData[14] = other[1];
                        dayData[15] = other[2];
                        dayData[16] = other[3];
                        dayData[17] = other[4];
                        dayData[18] = other[5];
                        dayData[19] = other[6];
                        dayData[20] = other[7];
                        //用户Pid去重 要第一个
                        dayData[21] = raw[14];
                        String monthData = map.get(meterId);
                        if (monthData == null) {
                            StringJoiner sj = new StringJoiner("%");
                            for (String dayDatum : dayData) {
                                sj.add(dayDatum);
                            }
                            map.put(meterId, sj.toString());
                        }
                        else {
                            String[] monthDataArray = monthData.split("%");
                            //数值累加
                            numberAccumulate(monthDataArray, dayData, 2, 4, 6, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
                            //字符串去重累加
//                        stringAccumulate(monthData, dayData, 7);
                            compareExtremum(monthDataArray, dayData, 7, 9);
                            StringJoiner sj = new StringJoiner("%");
                            for (String dayDatum : monthDataArray) {
                                sj.add(dayDatum);
                            }
                            map.put(meterId, sj.toString());
                        }
                        if (tmpCount == 100000) {
                            log.info("已执行10万条，当前总执行条:{} 样例:" + map.get(meterId), total);
                            tmpCount = 0;
                        }
                    }
                    catch (Exception e) {
                        removes.add(raw);
//                        log.error("源数据异常：{}", Arrays.toString(raw));
                    }
                }

            }
        }


        for (String str : map.values()) {
            String[] value = str.split("%");
            value[1] = "0";
            value[3] = "0";
            value[5] = "0";
            try {
                double v3 = NumberUtil.isNumber(value[2]) ? Double.parseDouble(value[2]) : 0d;
                double v5 = NumberUtil.isNumber(value[4]) ? Double.parseDouble(value[4]) : 0d;
                double v7 = NumberUtil.isNumber(value[6]) ? Double.parseDouble(value[6]) : 0d;
                if (v3 > 0) {
                    value[1] = String.valueOf(1 - (v5 / v3 - v7 / v3));
                    value[3] = String.valueOf(v5 / v3);
                    value[5] = String.valueOf(v7 / v3);
                }
                StringJoiner sj = new StringJoiner("\t");
                for (String dayDatum : value) {
                    sj.add(dayDatum);
                }
                map.put(value[0], sj.toString());
            }
            catch (Exception e) {
                log.error("统计异常数据：" + Arrays.toString(value));
                e.printStackTrace();
            }
        }
        log.info("总读取行数:{}", total);
        log.info("丢弃的行数:{}", removes.size());
        for (String[] remove : removes) {
            log.info("丢弃行数组:{}", Arrays.toString(remove));
        }

        long read_e = System.currentTimeMillis() - read_s;
        log.info("读完成，总耗时:{}", read_e);
        log.info("开写");
        long      write_s = System.currentTimeMillis();
        CsvWriter writer  = CsvUtil.getWriter(csvDirPath + "/monthData.csv", StandardCharsets.UTF_8);
        writer.write(map.values());
        writer.close();
        long write_e = System.currentTimeMillis() - write_s;
        log.info("写完成，总耗时:{}", write_e);
        log.info("读耗时:{}\t写耗时:{}\t写记录数:{}", read_e, write_e, map.size());

    }

    public static void numberAccumulate(String[] monthData, String[] dayData, int... index) {
        for (int i : index) {
            double m = !NumberUtil.isNumber(monthData[i]) ? 0d : Double.parseDouble(monthData[i]);
            double d = !NumberUtil.isNumber(dayData[i]) ? 0d : Double.parseDouble(dayData[i]);
            monthData[i] = Double.toString(m + d);
        }
    }

    public static void stringAccumulate(String[] monthData, String[] dayData, int... index) {
        for (int i : index) {
            String   m   = monthData[i];
            String   d   = dayData[i];
            String[] m_s = m.split(",");
            String[] m_d = d.split(",");

            Set<String> set = new HashSet<>();
            Stream.of(m_s, m_d).flatMap((Function<String[], Stream<String>>) Stream::of).forEach(set::add);
            StringJoiner sj = new StringJoiner(",");
            for (String s : set) {
                sj.add(s);
            }
            monthData[i] = sj.toString();
        }
    }

    public static void compareExtremum(String[] monthData, String[] dayData, int... index) {
        for (int i : index) {
            String m = !NumberUtil.isNumber(monthData[i]) ? null : monthData[i];
            String d = !NumberUtil.isNumber(dayData[i]) ? null : dayData[i];
            //如果当前月统计值为null，直接让他等于日统计值
            if (m == null) {
                monthData[i]     = d;
                monthData[i + 1] = dayData[i + 1];
                continue;
            }
            //如果当前日统计值为null，跳过比较
            if (d == null) {
                continue;
            }
            //2个都有值，比较大小
            double md = Double.parseDouble(m);
            double dd = Double.parseDouble(d);
            if (i == 7) {//最大值
                //月统计最大值小于日统计最大值
                if (md < dd) {
                    monthData[i]     = d;
                    monthData[i + 1] = dayData[i + 1];
                }
            }
            if (i == 9) {//最小值
                //月统计最小值大于日统计最小值
                if (md > dd) {
                    monthData[i]     = d;
                    monthData[i + 1] = dayData[i + 1];
                }
            }
        }
    }


    /**
     * 0:237.9,1:238.9,2:238.9,3:238.1,4:237.7,5:240.0,6:240.5,
     * 7:239.4,8:239.7,9:237.2,10:236.5,11:238.3,12:236.3,13:236.6,14:238.2,
     * 15:239.6,16:237.6,17:237.0,18:236.1,19:235.5,20:236.0,21:239.1,22:237.5
     *
     * @param data 1,2,3,4
     *             1,2
     *             1,2,3
     *             1,3
     *             <p>
     *             id , sbid , up_time , down_time , monitor_time ,device_type ,valid_date_time , cons_type  ,high_voltage , low_voltage , severe_high_voltage , severely_low_voltage
     *             <p>
     *             <p>
     *             <p>
     *             1.高电压次数  2.低电压次数  3.严重高次数 4.严重低次数 5.高电压时长 6.低电压时长 7严重高时长 8严重低时长
     *             <p>
     *             4:235.7,8:235.7
     * @return
     */
    public static String[] get(String[] data, Date date) {


        String[] yh = new String[12];

        for (int i = 0; i < 12; i++) {
            yh[i] = null;
        }

        //高电压数组
        ArrayList<Integer> gList = new ArrayList<>();
        //低电压数组
        ArrayList<Integer> dList = new ArrayList<>();
        //严重高数组
        ArrayList<Integer> sgList = new ArrayList<>();
        //严重低数组
        ArrayList<Integer> sdList = new ArrayList<>();

        //长期高用户
        ArrayList<YhVo> cgYhs = new ArrayList<>();

        //长期低用户
        ArrayList<YhVo> cdYhs = new ArrayList<>();
        try {
            String consType = data[15];


            String maxVolt     = null;
            String maxDateTime = null;
            String minVolt     = null;
            String minDateTime = null;


            String[] split = consType.split(",");
            for (String s : split) {
                //用户为高电压类型
                if (s.equals("1")) {
                    String g = data[10];
                    //高电压数组
                    pb(gList, g, "1", cgYhs);
                    pb(dList, g, "1", cdYhs);
                }
                //用户为低电压类型
                if (s.equals("2")) {
                    String g = data[11];
                    //低电压数组
                    cdYhs.clear();
                    pb(dList, g, "1", cdYhs);
                }
            }

            /**
             * 1.高电压次数  2.低电压次数  3.严重高次数 4.严重低次数
             * 5.高电压时长 6.低电压时长 7严重高时长 8严重低时长
             * 9 最大值 10 最大值时间 11最小值  12最小值时间
             */
            Integer g  = FormulaUtils.isLxNum24(gList, 1);
            Integer d  = FormulaUtils.isLxNum24(dList, 1);
            Integer sg = FormulaUtils.isLxNum24(sgList, 1);
            Integer sd = FormulaUtils.isLxNum24(sdList, 1);


            if (cgYhs.size() > 0) {
                //长期高电压数组
                List<YhVo> order = order(cgYhs);
                YhVo       max   = order.get(order.size() - 1);
                //最大值时间
                maxDateTime = DateUtil.offsetMinute(date, (max.getIndex() - 1) * 15).toString();
                maxVolt     = max.getVolt().toString();

            }
            if (cdYhs.size() > 0) {
                //长期低电压数组
                List<YhVo> voltMins = order(cdYhs);
                YhVo       min      = voltMins.get(0);
                //最小值时间
                minDateTime = DateUtil.offsetMinute(date, (min.getIndex() - 1) * 15).toString();
                minVolt     = min.getVolt().toString();
            }


            yh[0]  = String.valueOf(g);
            yh[1]  = String.valueOf(d);
            yh[2]  = String.valueOf(sg);
            yh[3]  = String.valueOf(sd);
            yh[4]  = String.valueOf(gList.size() * 60);
            yh[5]  = String.valueOf(dList.size() * 60);
            yh[6]  = String.valueOf(sgList.size() * 60);
            yh[7]  = String.valueOf(sdList.size() * 60);
            yh[8]  = maxVolt;
            yh[9]  = maxDateTime;
            yh[10] = minVolt;
            yh[11] = minDateTime;
        }
        catch (Exception e) {
            log.error(Arrays.toString(data));
//            e.printStackTrace();
        }
        return yh;
    }

    public static List<YhVo> order(List<YhVo> list) {
        return list.stream().sorted(Comparator.comparing(YhVo::getVolt)).collect(Collectors.toList());
    }


    private static void pb(ArrayList<Integer> sdList, String g, String tag, List<YhVo> yhVos) {

        String[] gstrings = g.split(",");
        for (String gstring : gstrings) {
            gstring = gstring.replaceAll("\"", "");
            YhVo     yhVo   = new YhVo();
            String[] indexs = gstring.split(":");
            String   index  = indexs[0];
            yhVo.setIndex(Integer.parseInt(index));
            if (tag.equals("2")) {
                if (indexs.length > 1) {
                    String dy = indexs[1];
                    if (Double.parseDouble(dy) > 176D) {
                        continue;
                    }
                    yhVo.setVolt(Double.parseDouble(dy));
                }
            }
            else if (tag.equals("1")) {
                if (indexs.length > 1) {
                    String dy = indexs[1];
                    yhVo.setVolt(Double.parseDouble(dy));
                }
            }
            if (NumberUtil.isNumber(index)) {
                sdList.add(Integer.parseInt(index));
            }

            if (yhVos != null) {
                yhVos.add(yhVo);
            }
        }

    }

}
